package cn.edu.sdjzu.knoverse.service.impl;

import cn.edu.sdjzu.knoverse.constant.EdgeConstant;
import cn.edu.sdjzu.knoverse.model.entity.kg.CourseNode;
import cn.edu.sdjzu.knoverse.model.entity.kg.KnowledgeNode;
import cn.edu.sdjzu.knoverse.model.vo.kg.KnowledgeTreeVO;
import cn.edu.sdjzu.knoverse.model.vo.result.PageResult;
import cn.edu.sdjzu.knoverse.repository.CourseRepository;
import cn.edu.sdjzu.knoverse.repository.KnowledgeRepository;
import cn.edu.sdjzu.knoverse.service.KnowledgeService;
import cn.edu.sdjzu.knoverse.utils.exception.CustomException;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.neo4j.cypherdsl.core.Condition;
import org.neo4j.cypherdsl.core.Cypher;
import org.neo4j.cypherdsl.core.Node;
import org.neo4j.cypherdsl.core.Statement;
import org.neo4j.driver.types.MapAccessor;
import org.neo4j.driver.types.TypeSystem;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.neo4j.core.Neo4jClient;
import org.springframework.data.neo4j.core.mapping.Neo4jMappingContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class KnowledgeServiceImpl implements KnowledgeService {

    private final KnowledgeRepository knowledgeRepository;
    private final CourseRepository courseRepository;
    private final Neo4jClient neo4jClient;
    private final Neo4jMappingContext neo4jMappingContext;

    @Override
    @Transactional
    public KnowledgeNode createKnowledge(KnowledgeNode knowledge, Long courseId) {
        // 检查课程是否存在
        CourseNode course = courseRepository.findById(courseId)
                .orElseThrow(() -> new CustomException("课程不存在"));
        
        // 保存知识点
        KnowledgeNode savedKnowledge = knowledgeRepository.save(knowledge);
        
        // 获取COURSE_KNOWLEDGE关系的基本信息
        EdgeConstant courseKnowledgeEdge = EdgeConstant.COURSE_KNOWLEDGE;
        String edgeName = courseKnowledgeEdge.getName();
        String edgeDescription = courseKnowledgeEdge.getDescription();
        
        // 创建课程到知识点的关系
        knowledgeRepository.createCourseKnowledgeRelationship(
                courseId, 
                savedKnowledge.getNodeId(), 
                edgeName, 
                edgeDescription
        );
        
        return savedKnowledge;
    }

    @Override
    @Transactional
    public KnowledgeNode updateKnowledge(KnowledgeNode knowledge) {
        KnowledgeNode existingKnowledge = getKnowledge(knowledge.getNodeId());
        if (existingKnowledge == null) {
            throw new CustomException("知识点不存在");
        }
        return knowledgeRepository.save(knowledge);
    }

    @Override
    @Transactional
    public void deleteKnowledge(Long id) {
        if (!knowledgeRepository.existsById(id)) {
            throw new CustomException("知识点不存在");
        }
        knowledgeRepository.deleteById(id);
    }

    @Override
    public KnowledgeNode getKnowledge(Long id) {
        KnowledgeNode knowledge = knowledgeRepository.findById(id)
                .orElseThrow(() -> new CustomException("知识点不存在"));
        
        // 查询知识点所属的课程
        CourseNode course = knowledgeRepository.findCourseByKnowledgeId(id);
        if (course != null) {
            knowledge.setCourseNode(course);
            knowledge.setCourseId(course.getNodeId());
        }
        
        return knowledge;
    }

    @Override
    public List<KnowledgeNode> getAllKnowledge() {
        // 获取所有知识点
        List<KnowledgeNode> knowledgeNodes = knowledgeRepository.findAll();
        
        // 为每个知识点填充课程信息
        knowledgeNodes.forEach(knowledge -> {
            CourseNode course = knowledgeRepository.findCourseByKnowledgeId(knowledge.getNodeId());
            if (course != null) {
                knowledge.setCourseNode(course);
                knowledge.setCourseId(course.getNodeId());
            }
        });
        
        return knowledgeNodes;
    }
    
    @Override
    public PageResult<KnowledgeNode> getKnowledgeList(String name, String summary, Integer level, Long courseId, Integer currentPage, Integer pageSize) {
        // 构建排序规则：按更新时间降序
        Sort sort = Sort.by(Sort.Direction.DESC, "updateTime");
        
        // 创建分页请求对象
        Pageable pageable = PageRequest.of(currentPage - 1, pageSize);

        // 使用CypherDSL构建查询
        Node k = Cypher.node("Knowledge").named("k");
        Node c = Cypher.node("Course").named("c");
        
        // 构建基础查询条件
        Condition conditions = Cypher.noCondition();
        
        if (StringUtils.isNotBlank(name)) {
            conditions = conditions.and(k.property("name").contains(Cypher.literalOf(name)));
        }
        
        if (StringUtils.isNotBlank(summary)) {
            conditions = conditions.and(k.property("summary").contains(Cypher.literalOf(summary)));
        }
        
        if (level != null) {
            conditions = conditions.and(k.property("level").isEqualTo(Cypher.literalOf(level)));
        }

        // 构建查询语句
        Statement statement;
        if (courseId != null) {
            statement = Cypher.match(c.relationshipTo(k, "COURSE_KNOWLEDGE"))
                    .where(c.property("nodeId").isEqualTo(Cypher.literalOf(courseId)))
                    .and(conditions)
                    .returningDistinct(k, c)
                    .orderBy(k.property("updateTime").descending())
                    .skip(pageable.getOffset())
                    .limit(pageable.getPageSize())
                    .build();
        } else {
            statement = Cypher.match(c.relationshipTo(k, "COURSE_KNOWLEDGE"))
                    .where(conditions)
                    .returningDistinct(k, c)
                    .orderBy(k.property("updateTime").descending())
                    .skip(pageable.getOffset())
                    .limit(pageable.getPageSize())
                    .build();
        }

        // 构建计数查询
        Statement countStatement;
        if (courseId != null) {
            countStatement = Cypher.match(c.relationshipTo(k, "COURSE_KNOWLEDGE"))
                    .where(c.property("nodeId").isEqualTo(Cypher.literalOf(courseId)))
                    .and(conditions)
                    .returningDistinct(Cypher.count(k))
                    .build();
        } else {
            countStatement = Cypher.match(c.relationshipTo(k, "COURSE_KNOWLEDGE"))
                    .where(conditions)
                    .returningDistinct(Cypher.count(k))
                    .build();
        }

        // 获取KnowledgeNode和CourseNode的映射函数
        BiFunction<TypeSystem, MapAccessor, KnowledgeNode> knowledgeMappingFunction = 
            neo4jMappingContext.getRequiredMappingFunctionFor(KnowledgeNode.class);
        BiFunction<TypeSystem, MapAccessor, CourseNode> courseMappingFunction = 
            neo4jMappingContext.getRequiredMappingFunctionFor(CourseNode.class);

        // 执行查询
        List<KnowledgeNode> knowledgeNodes = neo4jClient.query(statement.getCypher())
                .fetchAs(KnowledgeNode.class)
                .mappedBy((typeSystem, record) -> {
                    KnowledgeNode knowledge = knowledgeMappingFunction.apply(typeSystem, record.get("k").asNode());
                    CourseNode course = courseMappingFunction.apply(typeSystem, record.get("c").asNode());
                    knowledge.setCourseNode(course);
                    knowledge.setCourseId(course.getNodeId());
                    return knowledge;
                })
                .all()
                .stream()
                .toList();

        // 执行计数查询
        Optional<Long> total = neo4jClient.query(countStatement.getCypher())
                .fetchAs(Long.class)
                .mappedBy((typeSystem, record) -> record.get(0).asLong())
                .one();

        // 构建返回结果
        return PageResult.<KnowledgeNode>builder()
                .list(knowledgeNodes)
                .total(total.orElse(0L))
                .pageNo(Long.valueOf(currentPage))
                .pageSize(Long.valueOf(pageSize))
                .build();
    }

    @Override
    public Set<KnowledgeNode> getKnowledgeByCourse(Long courseId) {
        // 检查课程是否存在
        if (!courseRepository.existsById(courseId)) {
            throw new CustomException("课程不存在");
        }
        
        // 获取课程下的所有知识点
        return knowledgeRepository.findByCourseId(courseId);
    }
    
    @Override
    @Transactional
    public void updatePreKnowledge(Long knowledgeId, List<Long> preKnowledgeIds) {
        // 检查当前知识点是否存在
        KnowledgeNode knowledge = getKnowledge(knowledgeId);
        
        // 验证前置知识点列表中不包含当前知识点自身
        if (preKnowledgeIds.contains(knowledgeId)) {
            throw new CustomException("前置知识点不能包含当前知识点自身");
        }
        
        // 验证所有前置知识点是否存在
        for (Long preKnowledgeId : preKnowledgeIds) {
            KnowledgeNode preKnowledge = getKnowledge(preKnowledgeId);
            
            // 检查添加此前置知识点是否会导致循环依赖
            if (knowledgeRepository.wouldCreateCyclicDependency(knowledgeId, preKnowledgeId)) {
                throw new CustomException("添加前置知识点 '" + preKnowledge.getName() + "' 会导致循环依赖，无法添加");
            }
        }
        
        // 删除当前知识点的所有前置知识点关系
        knowledgeRepository.deletePreKnowledgeRelationships(knowledgeId);
        
        // 获取PRE_KNOWLEDGE关系的基本信息
        EdgeConstant preEdge = EdgeConstant.PRE_KNOWLEDGE;
        String edgeName = preEdge.getName();
        String edgeDescription = preEdge.getDescription();
        
        // 创建新的前置知识点关系
        for (Long preKnowledgeId : preKnowledgeIds) {
            knowledgeRepository.createPreKnowledgeRelationship(knowledgeId, preKnowledgeId, edgeName, edgeDescription);
        }
    }
    
    @Override
    public Set<KnowledgeNode> getPreKnowledge(Long knowledgeId) {
        // 检查知识点是否存在
        if (!knowledgeRepository.existsById(knowledgeId)) {
            throw new CustomException("知识点不存在");
        }
        
        // 获取所有前置知识点
        Set<KnowledgeNode> preKnowledgeNodes = knowledgeRepository.findPreKnowledge(knowledgeId);
        
        // 为每个前置知识点填充课程信息
        preKnowledgeNodes.forEach(knowledge -> {
            CourseNode course = knowledgeRepository.findCourseByKnowledgeId(knowledge.getNodeId());
            if (course != null) {
                knowledge.setCourseNode(course);
                knowledge.setCourseId(course.getNodeId());
            }
        });
        
        return preKnowledgeNodes;
    }

    @Override
    public List<KnowledgeTreeVO> getKnowledgeTree(Long excludeKnowledgeId) {
        List<KnowledgeTreeVO> result = new ArrayList<>();
        
        // 获取所有课程
        List<CourseNode> courses = courseRepository.findAll();
        
        for (CourseNode course : courses) {
            KnowledgeTreeVO courseTree = new KnowledgeTreeVO();
            courseTree.setId("course-" + course.getNodeId());
            courseTree.setLabel(course.getName());
            
            // 获取该课程下的所有知识点
            Set<KnowledgeNode> knowledgeNodes = knowledgeRepository.findByCourseId(course.getNodeId());
            
            // 过滤掉指定排除的知识点
            List<KnowledgeTreeVO.KnowledgeTreeNodeVO> knowledgeNodeVOs = knowledgeNodes.stream()
                .filter(k -> excludeKnowledgeId == null || !k.getNodeId().equals(excludeKnowledgeId))
                .map(k -> {
                    KnowledgeTreeVO.KnowledgeTreeNodeVO node = new KnowledgeTreeVO.KnowledgeTreeNodeVO();
                    node.setId(String.valueOf(k.getNodeId()));
                    node.setLabel(k.getName());
                    node.setLevel(k.getLevel());
                    return node;
                })
                .collect(Collectors.toList());
            
            // 只添加有知识点的课程
            if (!knowledgeNodeVOs.isEmpty()) {
                courseTree.setChildren(knowledgeNodeVOs);
                result.add(courseTree);
            }
        }
        
        return result;
    }
    
    @Override
    public List<KnowledgeTreeVO> getKnowledgeTreeByTeacherId(Long teacherId, Long excludeKnowledgeId) {
        List<KnowledgeTreeVO> result = new ArrayList<>();
        
        // 获取教师教授的所有课程
        List<CourseNode> teacherCourses = courseRepository.findCoursesByTeacherId(teacherId);
        
        for (CourseNode course : teacherCourses) {
            KnowledgeTreeVO courseTree = new KnowledgeTreeVO();
            courseTree.setId("course-" + course.getNodeId());
            courseTree.setLabel(course.getName());
            
            // 获取该课程下的所有知识点
            Set<KnowledgeNode> knowledgeNodes = knowledgeRepository.findByCourseId(course.getNodeId());
            
            // 过滤掉指定排除的知识点
            List<KnowledgeTreeVO.KnowledgeTreeNodeVO> knowledgeNodeVOs = knowledgeNodes.stream()
                .filter(k -> excludeKnowledgeId == null || !k.getNodeId().equals(excludeKnowledgeId))
                .map(k -> {
                    KnowledgeTreeVO.KnowledgeTreeNodeVO node = new KnowledgeTreeVO.KnowledgeTreeNodeVO();
                    node.setId(String.valueOf(k.getNodeId()));
                    node.setLabel(k.getName());
                    node.setLevel(k.getLevel());
                    return node;
                })
                .collect(Collectors.toList());
            
            // 只添加有知识点的课程
            if (!knowledgeNodeVOs.isEmpty()) {
                courseTree.setChildren(knowledgeNodeVOs);
                result.add(courseTree);
            }
        }
        
        return result;
    }
} 